#include "Tuplets.h"
#include <stdlib.h>
#include <gc/gc.h>
Tuplet * give_me_new_tuplet(void){
	Tuplet * tmp;
	tmp = (Tuplet *) GC_MALLOC(sizeof(Tuplet));
	if(tmp == NULL){
		abort();
	}
	tmp -> coefficient = construct_number();
	return tmp;
}

Tuplet * childs_to_tuplets(enum OperatorType oper, ListOfChilds * childs){
	Tuplet * to_return = NULL;
	Multitree * a = NULL;
	Multitree * b = NULL;
	Tuplet * added = NULL;
	ListOfChilds * first = NULL;

	while(childs != NULL){
		added = give_me_new_tuplet();
		added->tree = copy_tree(childs->subtree);
		/*Copy tree to added. If it is a tree, that needs anything done to it, then do it.*/

		/*If we have multiplication, then if there is tree a^b and b is number, then do something.*/
		if(oper == MULTIPLY){
			if((added->tree->symbol.type == OPERATOR)
				&& (added->tree->symbol.oper == POWER)
				&& (added->tree->childs->next->subtree->symbol.type == NUMBER)){/*Second child of current tree is number*/
					/*Do not copy*/
					a = added->tree->childs->subtree; /*This is rest.*/
					b = added->tree->childs->next->subtree;
					/*assert(b->symbol.type == NUMBER);*/
					if (childs->inverted){
						/* Numbers are initialized in give_me_new_tuplet*/ 
						numbercpy(added->coefficient, b->symbol.number);
						numberopp(added->coefficient, added->coefficient);
					}else{
						numbercpy(added->coefficient, b->symbol.number);
					}
					/*delete first node of added (with listofchilds) and replace added with a.*/
					GC_FREE(added->tree->childs->next);
					GC_FREE(added->tree->childs);
					GC_FREE(added->tree);
					added->tree = a;
					/*We do not need b anymore. Since it is leaf...*/
					GC_FREE(b);
			}else{
				/*else just set coefficient to 1 or -1*/
				if (childs->inverted){
					inttonum(added->coefficient, -1);
				}else{
					inttonum(added->coefficient, 1);
				}
			}
		}else{
			/*assert(oper == PLUS);
			Similar to previous. However, now multiplication is operator that concerns us.
			Let the coeff. be 1 or -1 and then "edit" it.*/
			if(childs->inverted){
				inttonum(added->coefficient, -1);
			}else{
				inttonum(added->coefficient, 1);
			}
			/*If child is multiplication, that has number (since tree is sorted, the number would be first)*/
			if((added->tree->symbol.type == OPERATOR)
				&& (added->tree->symbol.oper == MULTIPLY)
				&& (added->tree->childs->subtree->symbol.type == NUMBER)){
					/*Remove number (first child) from added.*/
					first = added->tree->childs;
					added->tree->childs = added->tree->childs->next;
					
					/*Now coefficient depends on added->tree->childs->inverted.
					for example in x/2, the coefficient should be 1/2, not 2*/
					if(first->inverted){ 
						numberdiv(added->coefficient, added->coefficient, first->subtree->symbol.number);
					}else{
						numbermul(added->coefficient, added->coefficient, first->subtree->symbol.number);
					}
					GC_FREE(first->subtree); /*It is number, so it is leaf
					first->next is now added->tree->childs.*/
					GC_FREE(first);
					first = NULL;
					/*if tree is now multiplication with only one operand, then if it is not inverted, then pull it out.*/
					if((added->tree->childs->next == NULL) && (!(added->tree->childs->inverted))){
						Multitree * a = added->tree->childs->subtree;
						GC_FREE(added->tree->childs);
						GC_FREE(added->tree);
						added->tree = a;
					}
					/*It should be done!*/
			}
		}
		added->next = to_return;
		to_return = added;
		childs = childs->next;
	}
	return to_return;
}

Tuplet * add_tuplets(Tuplet * tuplet){
	Tuplet * to_return = NULL;
	while(tuplet != NULL){
		Tuplet * pass = to_return;
		while((pass != NULL) && (treecmp(pass->tree, tuplet->tree))){
			pass = pass->next;
		}
		if (pass != NULL){
			numberplus(pass->coefficient, pass->coefficient, tuplet->coefficient);;
		}else{
			pass = give_me_new_tuplet();
			pass->coefficient = tuplet->coefficient;
			pass->tree = copy_tree(tuplet->tree);
			pass->next = to_return;
			to_return = pass;
		}
		tuplet = tuplet->next;
	}
	return to_return;
}

void delete_tuplets(Tuplet * tuplet){
	if(tuplet == NULL){
		return;
	}else{
		delete_tuplets(tuplet->next);
		delete_tree(tuplet->tree);
		GC_FREE(tuplet);
	}
}

Tuplet * remove_null_tuplets(Tuplet * tuplet){
	Number * zero;
	Tuplet * to_return = NULL;
	zero = construct_number();
	inttonum(zero, 0);
	while(tuplet != NULL){
		if(numbercmp(tuplet->coefficient, zero) != 0){
			Tuplet * added = give_me_new_tuplet();
			added->coefficient = tuplet->coefficient;
			added->tree = copy_tree(tuplet->tree);
			added->next = to_return;
			to_return = added;
		}
		tuplet = tuplet->next;
	}
	return to_return;
}

ListOfChilds * tuplets_to_childs(enum OperatorType oper, Tuplet * tuplet){
	/*converts tuplets back to list of childs.*/
	Number * one = NULL;
	Number * minusone = NULL;
	Number * zero = NULL;
	Number * ncoef = NULL;
	ListOfChilds *to_return = NULL;
	ListOfChilds * added = NULL;
	ListOfChilds * first = NULL;
	Multitree * tree = NULL;
	Multitree * coef = NULL;
	one = construct_number();
	minusone = construct_number();
	zero = construct_number();
	ncoef = construct_number();
	inttonum(one, 1);
	inttonum(minusone, -1);
	inttonum(zero, 0);
	while(tuplet != NULL){
		added = give_me_empty_child();
		if((numbercmp(tuplet->coefficient, one) == 0) || (numbercmp(tuplet->coefficient, minusone) == 0)){
			added->subtree = copy_tree(tuplet->tree);
			if(numbercmp(tuplet->coefficient, minusone) == 0){
				added->inverted = 1;
			}else{
				added->inverted = 0;
			}
		}else{
			numbercpy(ncoef, tuplet->coefficient);
			if(numbercmp(tuplet->coefficient, zero) < 0){
				added->inverted = 1;
				numberopp(ncoef, ncoef);
			}else{
				added->inverted = 0;
			}
			tree = copy_tree(tuplet->tree);
			coef = treefromnum(ncoef);
			/*and now we just somehow connect tree and coef.
			How? It depends on oper. Is it PLUS or MULTIPLY?*/
			if(oper == PLUS){
				//If tree is multiplication, then add coef. to it as first child.
				if((tree->symbol.type == OPERATOR) && (tree->symbol.oper == MULTIPLY)){
					first = give_me_empty_child();
					first->inverted = 0;
					first->subtree = coef;
					first->next = tree->childs;
					tree->childs = first;
					added->subtree = tree;
				}else{
					/*Should be replaced with give_me_tree_with_two_childs, but neverind*/
					/*Create multiply node and attach coef and tree as childs
					Create multiply*/
					added->subtree = give_me_empty_tree();
					added->subtree->symbol.type = OPERATOR;
					added->subtree->symbol.oper = MULTIPLY;
					//Create two childs
					added->subtree->childs = give_me_empty_child();
					added->subtree->childs->next = give_me_empty_child();
					added->subtree->childs->next->next = NULL;
					//Second is tree
					added->subtree->childs->next->inverted = 0;
					added->subtree->childs->next->subtree = tree;
					//First is coef
					added->subtree->childs->inverted = 0;
					added->subtree->childs->subtree = coef;
				}
			}else{
				/*oper == MULTIPLY
				We just create POWER and attach coef and tree as sons.
				Same as previous. Except for the order of sons!*/
				added->subtree = give_me_empty_tree();
				added->subtree->symbol.type = OPERATOR;
				added->subtree->symbol.oper = POWER;
				/*Create two childs*/
				added->subtree->childs = give_me_empty_child();
				added->subtree->childs->next = give_me_empty_child();
				added->subtree->childs->next->next = NULL;
				/*Second is coef.*/
				added->subtree->childs->next->inverted = 0;
				added->subtree->childs->next->subtree = coef;
				/*First is tree*/
				added->subtree->childs->inverted = 0;
				added->subtree->childs->subtree = tree;
			}
		}/*coefficient == +/- 1*/
		added->next = to_return;
		to_return = added;
		tuplet = tuplet->next;
	}
	return to_return;
}
